////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_CORE_TIME_INL__
#define __WN_CORE_TIME_INL__

#ifndef __WN_CORE_TIME_H__
    #error "WNCore/inc/WNTime.inl should never be included directly. Please include WNCore/inc/WNTime.h instead"
#endif

#include "WNCore/inc/WNPlatform.h"
#include "WNCore/inc/WNTypes.h"
#include "WNCore/inc/WNTime.h"

#ifdef _WN_WINDOWS
    #include <windows.h>

    typedef ULONGLONG (WINAPI *__WN_GTC64_FUNCTION_T)();
#elif defined _WN_LINUX
    #include <sys/time.h>
#endif

WN_INLINE WN_UINT32 WNGetTime() {
    #ifdef _WN_WINDOWS
        return(static_cast<WN_UINT32>(GetTickCount()));
    #elif defined _WN_LINUX
        return(static_cast<WN_UINT32>(WNGetBigTime()));
    #endif
}

WN_INLINE WN_UINT64 WNGetBigTime() {
    #ifdef _WN_WINDOWS
        const HMODULE handle = GetModuleHandle("kernel32");
        const FARPROC address = GetProcAddress(handle, "GetTickCount64");
        const __WN_GTC64_FUNCTION_T GTC64 = reinterpret_cast<__WN_GTC64_FUNCTION_T>(address);

        if (GTC64 == WN_NULL) {
            LARGE_INTEGER timerFrequency;

            QueryPerformanceFrequency(&timerFrequency);

            LARGE_INTEGER timerValue;

            QueryPerformanceCounter(&timerValue);

            return(static_cast<WN_UINT64>((timerValue.QuadPart * 1000 / timerFrequency.QuadPart) + 0.5));
        } else {
            return(static_cast<WN_UINT64>(GTC64()));
        }
    #elif defined _WN_LINUX
        timeval time = {0};

        gettimeofday(&time, NULL);

        return(static_cast<WN_UINT64>((time.tv_sec * 1000 + time.tv_usec / 1000) + 0.5));
    #endif
}

#endif // __WN_CORE_TIME_INL__